﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.Creation;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.UI;
using YJKArch.ModifiedArea;
using YJKArch.Utils;
using YJKArchKernel.OutWallSearch;
using HYRevitCode.RevitTopologySuite;
using YJKRGeometry;
using TopologySearch;

namespace YJKArch.EditFloor.CreateFloor
{
	public class OffsetCurveManager
	{
		public OffsetCurveManager(ExternalCommandData InputCmd, SearchFloorForm Inputdlg)
		{
			this.m_Revit = InputCmd;
			this.m_CreateFloorForm = Inputdlg;
			this.m_doc = InputCmd.Application.ActiveUIDocument.Document;
		}

		public bool CreateFloor(List<WallData> lstInputOutWall, List<Level> lstInputLevel, List<Room> lstInputRooms)
		{
			List<Curve> list = new List<Curve>();
			List<List<Curve>> list2 = new List<List<Curve>>();
			new List<CurveInformationBean>();
			foreach (CurveInformationBean curveInformationBean in new RoomCurveManager(this.m_doc).GetCurveFormRooms(lstInputRooms, null))
			{
				list.Add(curveInformationBean.ThisCurve);
			}
			List<RevitPolygonDataBean> lstFindPolyDataBean = null;
			List<RevitPolygonDataBean> lstCreatedPolyDataBean = null;
			if (new RevitPolygonFinder().TryGetPolygon(list, out lstFindPolyDataBean, out lstCreatedPolyDataBean, true))
			{
				try
				{
					list2 = this.GetOutLoopOffsetCurves(lstFindPolyDataBean, lstCreatedPolyDataBean, lstInputOutWall);
				}
				catch (Exception)
				{
					return false;
				}
			}
			int num = 0;
			double num2 = Common.MMToFeet(this.m_CreateFloorForm.ElevationOffset);
			Autodesk.Revit.Creation.Document create = this.m_doc.Create;
			Transaction transaction = new Transaction(this.m_doc, "Create Floors");
			transaction.Start();
			bool result;
			try
			{
				foreach (List<Curve> list3 in list2)
				{
					CurveArray curveArray = new CurveArray();
					foreach (Curve curve in list3)
					{
						curveArray.Append(curve);
					}
					try
					{
						Floor floor = create.NewFloor(curveArray, this.m_CreateFloorForm.SelFloorType, lstInputLevel[this.m_CreateFloorForm.LevelIndex], false);
						if (floor != null)
						{
							floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(num2);
							num++;
						}
					}
					catch (Exception)
					{
					}
				}
				transaction.Commit();
				if (num > 0)
				{
					result = true;
				}
				else
				{
					result = false;
				}
			}
			catch (Exception)
			{
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				result = false;
			}
			return result;
		}

		private void FilterOutWallData(List<RevitPolygonDataBean> lstInputPolygonBean, ref List<WallData> lstInputOutWallData)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (RevitPolygonDataBean revitPolygonDataBean in lstInputPolygonBean)
			{
				foreach (Curve curve in revitPolygonDataBean.ShellCurveLoop)
				{
					list.AddRange(curve.Tessellate());
				}
			}
			for (int i = 0; i < lstInputOutWallData.Count; i++)
			{
				foreach (YJKRGeometry.EdgeInfo edgeInfo in lstInputOutWallData[i].GetOutWallSegmentCenterLine())
				{
					XYZ pt = null;
					if (edgeInfo.ConvertToCurve() is Line)
					{
						pt = YJKArch.Utils.Geometry.CalculatMidPoint(edgeInfo.ConvertToCurve() as Line);
					}
					else if (edgeInfo.ConvertToCurve() is Arc)
					{
						pt = YJKArch.Utils.Geometry.CalculatMidPoint(edgeInfo.ConvertToCurve() as Arc);
					}
					if (YJKArch.Utils.Geometry.PointInPloygon(list, pt, 0.0001, 0.0001) == 1)
					{
						lstInputOutWallData.Remove(lstInputOutWallData[i]);
						i--;
					}
				}
			}
		}

		private List<List<Curve>> GetOutLoopOffsetCurves(List<RevitPolygonDataBean> lstFindPolyDataBean, List<RevitPolygonDataBean> lstCreatedPolyDataBean, List<WallData> lstInputWallData)
		{
			List<List<Curve>> list = new List<List<Curve>>();
			List<KeyValuePair<Curve, double>> list2 = new List<KeyValuePair<Curve, double>>();
			double dEps = AssistFunc.mmToFeet(0.8);
			StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_Revit, dEps);
			if (this.m_CreateFloorForm.IsOutloop)
			{
				using (List<RevitPolygonDataBean>.Enumerator enumerator = lstCreatedPolyDataBean.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						RevitPolygonDataBean revitPolygonDataBean = enumerator.Current;
						if (revitPolygonDataBean.ShellCurveLoop != null)
						{
							list2.Clear();
							foreach (Curve curve in revitPolygonDataBean.ShellCurveLoop)
							{
								WallData inputData = null;
								if (this.IsOutWallCurve(curve, lstInputWallData, ref inputData))
								{
									list2.Add(this.OffsetCurve(inputData, curve));
								}
								else
								{
									list2.Add(new KeyValuePair<Curve, double>(curve, 0.0));
								}
							}
							try
							{
								list.Add(structureLoopSearcher.OffsetLoop(list2, true, false).First<List<Curve>>());
							}
							catch (Exception)
							{
							}
						}
					}
					return list;
				}
			}
			foreach (RevitPolygonDataBean revitPolygonDataBean2 in lstFindPolyDataBean)
			{
				if (revitPolygonDataBean2.ShellCurveLoop != null)
				{
					list2.Clear();
					foreach (Curve curve2 in revitPolygonDataBean2.ShellCurveLoop)
					{
						WallData inputData2 = null;
						if (this.IsOutWallCurve(curve2, lstInputWallData, ref inputData2))
						{
							list2.Add(this.OffsetCurve(inputData2, curve2));
						}
						else
						{
							list2.Add(new KeyValuePair<Curve, double>(curve2, 0.0));
						}
					}
					try
					{
						list.Add(structureLoopSearcher.OffsetLoop(list2, true, false).First<List<Curve>>());
					}
					catch (Exception)
					{
					}
				}
			}
			return list;
		}

		private bool IsOutWallCurve(Curve InputCv, List<WallData> lstInputOutWall, ref WallData tmpData)
		{
			YJKRGeometry.EdgeInfo edgeInfo = new YJKRGeometry.EdgeInfo(InputCv);
			foreach (WallData wallData in lstInputOutWall)
			{
				XYZ xyz = null;
				XYZ xyz2 = null;
				YJKRGeometry.Geometry.OverlapType overlapType = OverlapFinder.OverlapFind(new YJKRGeometry.EdgeInfo(((this.m_doc.GetElement(wallData.Id) as Wall).Location as LocationCurve).Curve), edgeInfo, ref xyz, ref xyz2);
				if (overlapType != YJKRGeometry.Geometry.OverlapType._OT_None && overlapType != YJKRGeometry.Geometry.OverlapType._OT_Linked && overlapType != YJKRGeometry.Geometry.OverlapType._OT_Part && wallData.IsOutWallWithCenterLineSegment(InputCv))
				{
					tmpData = wallData;
					return true;
				}
			}
			return false;
		}

		private KeyValuePair<Curve, double> OffsetCurve(WallData InputData, Curve InputCurve)
		{
			int num = 0;
			double num2 = 0.0;
			double num3 = Common.MMToFeet(this.m_CreateFloorForm.BoundaryOffset);
			KeyValuePair<Curve, double> result = default(KeyValuePair<Curve, double>);
			Wall wall = this.m_doc.GetElement(InputData.Id) as Wall;
			if (wall.WallType != null && wall.WallType.GetCompoundStructure() != null)
			{
				int firstCoreLayerIndex = wall.WallType.GetCompoundStructure().GetFirstCoreLayerIndex();
				foreach (CompoundStructureLayer compoundStructureLayer in wall.WallType.GetCompoundStructure().GetLayers())
				{
					if (num == firstCoreLayerIndex)
					{
						break;
					}
					num2 += compoundStructureLayer.Width;
					num++;
				}
				result = new KeyValuePair<Curve, double>(InputCurve, wall.Width / 2.0 - num2 + num3);
			}
			return result;
		}

		private ExternalCommandData m_Revit;

		private Autodesk.Revit.DB.Document m_doc;

		private SearchFloorForm m_CreateFloorForm;
	}
}
